#pragma once

#include <optional>
using std::optional;

using _OptChar = optional<char>;

static constexpr _OptChar __EPSILON = std::nullopt;
static constexpr auto __WHITE_SPACES = {_OptChar(' '), _OptChar('\t'), _OptChar('\n')};
static constexpr int __ID_EPSILON = 0;

const int __FAKE_END = -1; // make a fake ending char just like '$' in LR(1) parser

// #define __DEBUG
// #define __DEBUG_LV1
// #define __DEBUG_LV2

#define __PRINT_LINE_HINT(s)                                                             \
    std::cerr << "\n>>>>>>>>" << __FILE__ << " " << __LINE__ << ": " << s << "<<<<<<<<\n";


/**
 * Open a file stream and check if it's open
 * @param stream file stream
 * @param name file name, an empty string would do nothing
 * @param isOstream is output stream
 */ 
template <typename _Stream>
void __OPEN_AND_CHECK(_Stream &stream, const string &name, bool isOstream) {
    if(name.empty()){
        cout << "Empty file name\n";
        return;
    }
    if (isOstream)
        stream.open(name, std::fstream::out | std::fstream::trunc);
    else
        stream.open(name, std::fstream::in);
    if (!stream.is_open()) {
        cout << "Fail to open" << name << ".\nPrgram terminated.\n";
    }
}
